package com.itee.protocal.concent;



import com.itee.core.util.NumberCoder;
import com.itee.core.util.StringCoder;
import com.itee.protocal.BasePacket;
import com.itee.protocal.FnTools;
import com.itee.protocal.meta.Communication;
import com.itee.protocal.meta.SpeedRateUnit;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

/**
 * @author Administrator
 */
public class ConcentPacket extends BasePacket {

	public static final byte POS_BEGIN = 0x68;

	public static final byte POS_END = 0x16;

	/**
	 * 长度L
	 */
	private short length;

	private byte ctrl;

	/**
	 * 信息域
	 */
	private byte[] infoR;

	/**
	 * 源地址
	 */
	private byte[] source;


	/**
	 * 目标地址
	 */
	private byte[] destination;

	/**
	 * 中继地址
	 */
	private byte[][] relays;

	/**
	 * 应用功能码
	 */
	private byte afn;

	/**
	 * 信息类元DT1
	 */
	private byte dt1;

	/**
	 * 信息类组DT2
	 */
	private byte dt2;

	/**
	 * 数据单元
	 */
	private byte[] datas;

	public ConcentPacket(short length, byte ctrl, byte[] infoR) {
		super();
		this.length = length;
		this.ctrl = ctrl;
		this.infoR = infoR;
	}

	public ConcentPacket(byte ctrl, byte[] infoR) {
		super();
		this.ctrl = ctrl;
		this.infoR = infoR;
	}

	public ConcentPacket() {
		super();
	}

	public ConcentPacket(boolean dirUplink, boolean prmStart, Communication communication) {
		super();
		setDir(dirUplink);
		setPrm(prmStart);
		setCommunication(communication);
	}

	/**
	 * 表示此帧报文是否由通信模块发出的上行报文
	 * 
	 * @return
	 */
	public boolean isDirUplink() {
		return NumberCoder.specialBitIsOne(ctrl, 7);
	}

	/**
	 * 设置此帧报文是否由通信模块发出的上行报文
	 * 
	 * @param isUplink
	 */
	public void setDir(boolean isUplink) {
		this.ctrl = NumberCoder.specialBitToOne(ctrl, 7, isUplink);
	}

	/**
	 * 表示此帧报文来自启动站
	 * 
	 * @return
	 */
	public boolean isPrmStart() {
		return NumberCoder.specialBitIsOne(ctrl, 6);
	}

	/**
	 * 设置此帧报文来自启动站
	 * 
	 * @param isStart
	 */
	public void setPrm(boolean isStart) {
		this.ctrl = NumberCoder.specialBitToOne(ctrl, 6, isStart);
	}



	/**
	 * 设置通信方式
	 * 
	 * @param communication
	 */
	public void setCommunication(Communication communication) {
		this.ctrl = (byte) (ctrl & 0xc0);
		switch (communication) {
		case CENTRALIZED_ROUTING_CARRIER:
			this.ctrl = (byte) (ctrl | 0x01);
			break;
		case DISTRIBUTED_ROUTING_CARRIER:
			this.ctrl = (byte) (ctrl | 0x02);
			break;
		case BROADBAND_CARRIER:
			this.ctrl = (byte) (ctrl | 0x03);
			break;
		case MICRO_POWER_WIRELESS:
			this.ctrl = (byte) (ctrl | 0x0A);
			break;
		case ETHERNET:
			this.ctrl = (byte) (ctrl | 0x14);
			break;
		default:
			break;
		}
	}

	public Communication getCommunication() {
		byte communication = (byte) (this.ctrl & 0x3f);
		switch (communication) {
		case (byte) 0x01:
			return Communication.CENTRALIZED_ROUTING_CARRIER;
		case (byte) 0x02:
			return Communication.DISTRIBUTED_ROUTING_CARRIER;
		case (byte) 0x03:
			return Communication.BROADBAND_CARRIER;
		case (byte) 0x0A:
			return Communication.MICRO_POWER_WIRELESS;
		case (byte) 0x14:
			return Communication.ETHERNET;
		default:
			break;
		}
		return Communication.RETAIN;
	}

	/**
	 * 通信模块标识(false表示对主节点的操作，true表示对从节点操作)
	 * 
	 * @return
	 */
	public boolean isCommunicateModuleCode() {
		return NumberCoder.specialBitIsOne(infoR[0], 2);
	}

	/**
	 * 中继级别
	 * 
	 * @return
	 */
	public byte getRelayLevel() {
		byte level = (byte) (infoR[0] >>> 4);
		return level;
	}

	public short getLength() {
		return length;
	}

	public void setLength(short length) {
		this.length = length;
	}

	public byte getCtrl() {
		return ctrl;
	}

	public void setCtrl(byte ctrl) {
		this.ctrl = ctrl;
	}

	public byte getAfn() {
		return afn;
	}

	public void setAfn(byte afn) {
		this.afn = afn;
	}

	public void setFn(int fn) {
		byte[] dt = FnTools.convertFnToByte(fn);
		this.dt1 = dt[0];
		this.dt2 = dt[1];
	}

	public int getFn() {
		return FnTools.convertToFn(dt1, dt2);
	}

	public void setAfns(byte afn, int fn) {
		this.afn = afn;
		setFn(fn);
	}

	public byte[] getSource() {
		return source;
	}

	public void setSource(byte[] source) {
		this.source = source;
	}

	public byte[] getDestination() {
		return destination;
	}

	public void setDestination(byte[] destination) {
		this.destination = destination;
	}

	public byte[][] getRelays() {
		return relays;
	}

	public void setRelays(byte[][] relays) {
		this.relays = relays;
	}

	public byte[] getInfoR() {
		return infoR;
	}

	public void setInfoR(byte[] infoR) {
		this.infoR = infoR;
	}

	public void setInfoR(boolean attached, boolean communicateModuleCode) {
		this.infoR = new byte[6];
		if (attached) {
			infoR[0] = (byte) (infoR[0] | 0x02);
		}
		if (communicateModuleCode) {
			infoR[0] = (byte) (infoR[0] | 0x04);
		}
	}

	public void setSpeedRate(SpeedRateUnit rateUnit, short speed) {
		infoR[3] = (byte) (speed & 0x00FF);
		infoR[4] = (byte) (speed >>> 8);
		if (rateUnit == SpeedRateUnit.BPS) {
			infoR[3] = (byte) (infoR[3] & 0x7F);
		} else {
			infoR[3] = (byte) (infoR[3] | 0x80);
		}
	}

	public int getSeq() {
		return NumberCoder.getUnsignedByte(infoR[5]) ;
	}

	public void setSeq(byte seq) {
		this.infoR[5] = seq;
	}

	public byte getDt1() {
		return dt1;
	}

	public void setDt1(byte dt1) {
		this.dt1 = dt1;
	}

	public byte getDt2() {
		return dt2;
	}

	public void setDt2(byte dt2) {
		this.dt2 = dt2;
	}

	public byte[] getDatas() {
		return datas;
	}

	public void setDatas(byte[] datas) {
		this.datas = datas;
	}

	public byte[] toBytes() {
		length = (short) (getUserLength() + 6);
		ByteBuffer buffer = ByteBuffer.allocate(length);
		buffer.order(ByteOrder.LITTLE_ENDIAN);
		buffer.put(POS_BEGIN);
		buffer.putShort(length);
		buffer.put(ctrl);
		buffer.put(infoR);
		if (source != null) {
			buffer.put(source);
		}
		if (relays != null) {
			for (int i = 0; i < relays.length; i++) {
				buffer.put(relays[i]);
			}
		}
		if (destination != null) {
			buffer.put(destination);
		}
		buffer.put(afn);
		buffer.put(dt1);
		buffer.put(dt2);
		if (datas != null) {
			buffer.put(datas);
		}
		byte[] bytes = buffer.array();
		byte cs = 0;
		for (int i = 3; i < (bytes.length - 2); i++) {
			cs += bytes[i];
		}
		buffer.put(cs);
		buffer.put(POS_END);
		return buffer.array();
	}

	public int getUserLength() {
		int usrLen = 9;
		if (source != null) {
			usrLen += 6;
		}
		if (relays != null) {
			usrLen = usrLen + relays.length * 6;
		}
		if (destination != null) {
			usrLen += 6;
		}
		if (datas != null) {
			usrLen = usrLen + datas.length;
		}
		return usrLen;
	}

    /**路由运行状态
     * @return
     */
    public NetWorkRouteInfo getNetWorkRouteInfo(){
        if(afn == 0x10 &&getFn()==0x4){
            NetWorkRouteInfo netWorkRouteInfo= new NetWorkRouteInfo(datas);
            return netWorkRouteInfo;
        }else {
            return null;
        }
    }

    @Override
    public String toString(){
        return StringCoder.bytesToHexString(toBytes(), " ");
    }


}
